package org.example.netty.nio.Buffer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

public class ScatteringGathering {
    public static void main(String[] args) throws IOException {
        // 打开ServerSocketChannel用于监听客户端的连接
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        InetSocketAddress address = new InetSocketAddress(8899);
        serverSocketChannel.socket().bind(address);
        int messageLength = 2 + 3 + 4;
        // 创建三个ByteBuffer，每个ByteBuffer分配不同的长度,用于测试分散读取和聚集写入
        // 创建ByteBuffer数组，用于分散读取和聚集写入
        ByteBuffer[] buffers = new ByteBuffer[3];
        buffers[0] = ByteBuffer.allocate(2);
        buffers[1] = ByteBuffer.allocate(3);
        buffers[2] = ByteBuffer.allocate(4);
        // 等待客户端连接
        SocketChannel socketChannel = serverSocketChannel.accept();
        while (true) {
            int bytesRead = 0;

            while (bytesRead < messageLength) {
                // 读取客户端发送的数据，并将其分散到三个ByteBuffer中
                // 分散读取,分散读取指的是将数据从通道中读入到多个缓冲区，直到所有缓冲区都被填满为止
                // 分散读取是NIO的特性之一， 它允许我们从通道中读取数据到多个缓冲区中。
                // 分散读取通常用于处理来自客户端的复合消息，例如一个包含多个字段的消息。
                long r = socketChannel.read(buffers);
                bytesRead += r;
                System.out.println("bytesRead:" + bytesRead);
                Arrays.asList(buffers).stream().
                        map(buffer -> "position:" + buffer.position() + ",limit:" + buffer.limit()).forEach(System.out::println);
            }
            Arrays.asList(buffers).forEach(buffer -> {
                buffer.flip();
            });
            long bytesWritten = 0;
            while (bytesWritten < messageLength) {
                // 将数据从多个ByteBuffer中聚集写入到通道，直到所有缓冲区都被写空为止，
                // 聚集写入指的是将多个缓冲区中的数据合并后写到通道中。
                // 聚集写入是NIO的特性之一， 它允许我们将数据从多个缓冲区中写出到通道。
                // 聚集写入通常用于将来自客户端的复合消息组装成一个完整的消息。
                long r = socketChannel.write(buffers);
                bytesWritten += r;
            }
            Arrays.asList(buffers).forEach(buffer -> {
                buffer.clear();
            });
            System.out.println("bytesRead:" + bytesRead + ",bytesWritten:" + bytesWritten + ",messageLength:" + messageLength);
        }
    }
}
